//package com.liuqianfei.markme.rules.core;
//
//import com.liuqianfei.markme.common.Utils;
//import com.liuqianfei.markme.core.Token;
//import com.liuqianfei.markme.rules.AbstractState;
//import com.liuqianfei.markme.rules.IAction;
//import com.liuqianfei.util.RegExpUtil;
//
//import java.util.ArrayList;
//import java.util.List;
//
///**
// * Convert straight quotation marks to typographic ones
// * @author liuqianfei
// */
//public class SmartquotesAction implements IAction
//{
//    String QUOTE_TEST_RE = "['\"]";
//    String QUOTE_RE = "['\"]"; ///g
//    char APOSTROPHE = '\u2019'; /* ’ */
//
//    private String replaceAt(String str, int index, char ch)
//    {
//        return str.substring(0, index) + ch + str.substring(index + 1);
//    }
//
//    private void processInlines(List<Token> tokens, AbstractState state)
//    {
//        Token token;
//        String text;
//        boolean t, canOpen, canClose, isSingle, isLastPunctChar, isNextPunctChar, isLastWhiteSpace, isNextWhiteSpace;
//        char lastChar, nextChar, openQuote, closeQuote;
//        int pos, max, thisLevel, j;
//
//        SmartquotesStack item;
//        List<SmartquotesStack> stack = new ArrayList<>();
//
//        for (int i = 0; i < tokens.size(); i++)
//        {
//            token = tokens.get(i);
//
//            thisLevel = tokens.get(i).level;
//
//            for (j = stack.size() - 1; j >= 0; j--)
//            {
//                if (stack.get(j).level <= thisLevel) { break; }
//            }
////            stack.size() = j + 1;
//
//            if (!"text".equals(token.type)) { continue; }
//
//            text = token.content;
//            pos = 0;
//            max = text.length();
//
//            /*eslint no-labels:0,block-scoped-var:0*/
//            OUTER:
//            while (pos < max)
//            {
//                QUOTE_RE.lastIndex = pos;
//                t = QUOTE_RE.exec(text);
//                if (!t) { break; }
//
//                canOpen = canClose = true;
//                pos = t.index + 1;
//                isSingle = (t[0] === "'");
//
//                // Find previous character,
//                // default to space if it's the beginning of the line
//                //
//                lastChar = 0x20;
//
//                if (t.index - 1 >= 0)
//                {
//                    lastChar = text.charAt(t.index - 1);
//                }
//                else
//                {
//                    for (j = i - 1; j >= 0; j--)
//                    {
//                        if (!"text".equals(tokens.get(j).type)) { continue; }
//
//                        lastChar = tokens.get(j).content.charAt(tokens.get(j).content.length() - 1);
//                        break;
//                    }
//                }
//
//                // Find next character,
//                // default to space if it's the end of the line
//                //
//                nextChar = 0x20;
//
//                if (pos < max)
//                {
//                    nextChar = text.charAt(pos);
//                }
//                else
//                {
//                    for (j = i + 1; j < tokens.size(); j++)
//                    {
//                        if (!"text".equals(tokens.get(j).type)) { continue; }
//
//                        nextChar = tokens.get(j).content.charAt(0);
//                        break;
//                    }
//                }
//
//                isLastPunctChar = Utils.isMdAsciiPunct(lastChar) || Utils.isPunctChar(String.valueOf(lastChar));
//                isNextPunctChar = Utils.isMdAsciiPunct(nextChar) || Utils.isPunctChar(String.valueOf(nextChar));
//
//                isLastWhiteSpace = Utils.isWhiteSpace(lastChar);
//                isNextWhiteSpace = Utils.isWhiteSpace(nextChar);
//
//                if (isNextWhiteSpace)
//                {
//                    canOpen = false;
//                }
//                else if (isNextPunctChar)
//                {
//                    if (!(isLastWhiteSpace || isLastPunctChar))
//                    {
//                        canOpen = false;
//                    }
//                }
//
//                if (isLastWhiteSpace)
//                {
//                    canClose = false;
//                }
//                else if (isLastPunctChar)
//                {
//                    if (!(isNextWhiteSpace || isNextPunctChar))
//                    {
//                        canClose = false;
//                    }
//                }
//
//                if (nextChar == 0x22 /* " */ && t[0] == '"')
//                {
//                    if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */)
//                    {
//                        // special case: 1"" - count first quote as an inch
//                        canClose = canOpen = false;
//                    }
//                }
//
//                if (canOpen && canClose)
//                {
//                    // treat this as the middle of the word
//                    canOpen = false;
//                    canClose = isNextPunctChar;
//                }
//
//                if (!canOpen && !canClose)
//                {
//                    // middle of word
//                    if (isSingle)
//                    {
//                        token.content = replaceAt(token.content, t.index, APOSTROPHE);
//                    }
//                    continue;
//                }
//
//                if (canClose)
//                {
//                    // this could be a closing quote, rewind the stack to get a match
//                    for (j = stack.size() - 1; j >= 0; j--)
//                    {
//                        item = stack.get(j);
//                        if (stack.get(j).level < thisLevel) { break; }
//                        if (item.single == isSingle && stack.get(j).level == thisLevel)
//                        {
//                            item = stack.get(j);
//
//                            if (isSingle)
//                            {
//                                openQuote = state.getMd().configuration.quotes[2];
//                                closeQuote = state.getMd().configuration.quotes[3];
//                            }
//                            else
//                            {
//                                openQuote = state.getMd().configuration.quotes[0];
//                                closeQuote = state.getMd().configuration.quotes[1];
//                            }
//
//                            // replace token.content *before* tokens[item.token].content,
//                            // because, if they are pointing at the same token, replaceAt
//                            // could mess up indices when quote length != 1
//                            token.content = replaceAt(token.content, t.index, closeQuote);
//                            tokens.get(item.token).content = replaceAt(tokens.get(item.token).content, item.pos, openQuote);
//
//                            pos += closeQuote.length - 1;
//                            if (item.token == i) { pos += openQuote.length - 1; }
//
//                            text = token.content;
//                            max = text.length();
//
////                            stack.size() = j;
//                            continue OUTER;
//                        }
//                    }
//                }
//
//                if (canOpen)
//                {
//                    SmartquotesStack smartquotesStack = new SmartquotesStack();
//                    smartquotesStack.token = i;
//                    smartquotesStack.pos = t.index;
//                    smartquotesStack.single = isSingle;
//                    smartquotesStack.level = thisLevel;
//                    stack.add(smartquotesStack);
//                }
//                else if (canClose && isSingle)
//                {
//                    token.content = replaceAt(token.content, t.index, APOSTROPHE);
//                }
//            }
//        }
//    }
//
//    @Override
//    public boolean parse(AbstractState state, boolean silent, int startLine, int endLine)
//    {
//        /*eslint max-depth:0*/
//        int blkIdx;
//
//        if (!state.getMd().configuration.typographer)
//            return false;// FIXME I fixed it
//
//        for (blkIdx = state.getTokens().size() - 1; blkIdx >= 0; blkIdx--)
//        {
//            if (!"inline".equals(state.getToken(blkIdx).type) || !RegExpUtil.match(QUOTE_TEST_RE, state.getToken(blkIdx).content, false))
//                continue;
//
//            processInlines(state.getToken(blkIdx).children, state);
//        }
//
//        return true;
//    }
//}
//
//class SmartquotesStack
//{
//    int token;
//    int pos;
//    boolean single;
//    int level;
//}